home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / hlbsp / qbsp.cpp < prev    next >
C/C++ Source or Header  |  2002-12-09  |  39KB  |  1,324 lines

  1. /*
  2.  
  3.     BINARY SPACE PARTITION    -aka-    B S P
  4.  
  5.     Code based on original code from Valve Software, 
  6.     Modified by Sean "Zoner" Cavanaugh (seanc@gearboxsoftware.com) with permission.
  7.     Modified by Tony "Merl" Moore (merlinis@bigpond.net.au) [AJM]
  8.     
  9. */
  10.  
  11. #ifdef SYSTEM_WIN32
  12. #define WIN32_LEAN_AND_MEAN
  13. #include <windows.h>
  14. #endif
  15.  
  16. #include "bsp5.h"
  17.  
  18. /*
  19.  
  20.  NOTES
  21.  
  22.  
  23. */
  24.  
  25. static FILE*    polyfiles[NUM_HULLS];
  26. int             g_hullnum = 0;
  27.  
  28. static face_t*  validfaces[MAX_MAP_PLANES];
  29.  
  30. char            g_bspfilename[_MAX_PATH];
  31. char            g_pointfilename[_MAX_PATH];
  32. char            g_linefilename[_MAX_PATH];
  33. char            g_portfilename[_MAX_PATH];
  34.  
  35. // command line flags
  36. bool            g_nofill = DEFAULT_NOFILL;      // dont fill "-nofill"
  37. bool            g_notjunc = DEFAULT_NOTJUNC;
  38. bool            g_noclip = DEFAULT_NOCLIP;      // no clipping hull "-noclip"
  39. bool            g_chart = DEFAULT_CHART;        // print out chart? "-chart"
  40. bool            g_estimate = DEFAULT_ESTIMATE;  // estimate mode "-estimate"
  41. bool            g_info = DEFAULT_INFO;
  42. bool            g_bLeakOnly = DEFAULT_LEAKONLY; // leakonly mode "-leakonly"
  43. bool            g_bLeaked = false; 
  44. int             g_subdivide_size = DEFAULT_SUBDIVIDE_SIZE;
  45.  
  46. #ifdef ZHLT_NULLTEX // AJM
  47. bool            g_bUseNullTex = DEFAULT_NULLTEX; // "-nonulltex"
  48. #endif
  49.  
  50. #ifdef ZHLT_DETAIL // AJM
  51. bool            g_bDetailBrushes = DEFAULT_DETAIL; // "-nodetail"
  52. #endif
  53.  
  54. #ifdef ZHLT_PROGRESSFILE // AJM
  55. char*           g_progressfile = DEFAULT_PROGRESSFILE; // "-progressfile path"
  56. #endif
  57.  
  58. #ifdef ZHLT_INFO_COMPILE_PARAMETERS// AJM
  59. // =====================================================================================
  60. //  GetParamsFromEnt
  61. //      this function is called from parseentity when it encounters the 
  62. //      info_compile_parameters entity. each tool should have its own version of this
  63. //      to handle its own specific settings.
  64. // =====================================================================================
  65. void            GetParamsFromEnt(entity_t* mapent)
  66. {
  67.     int iTmp;
  68.  
  69.     Log("\nCompile Settings detected from info_compile_parameters entity\n");
  70.  
  71.     // verbose(choices) : "Verbose compile messages" : 0 = [ 0 : "Off" 1 : "On" ]
  72.     iTmp = IntForKey(mapent, "verbose");
  73.     if (iTmp == 1)
  74.     {
  75.         g_verbose = true;
  76.     }
  77.     else if (iTmp == 0)
  78.     {
  79.         g_verbose = false;
  80.     }
  81.     Log("%30s [ %-9s ]\n", "Compile Option", "setting");
  82.     Log("%30s [ %-9s ]\n", "Verbose Compile Messages", g_verbose ? "on" : "off");
  83.  
  84.     // estimate(choices) :"Estimate Compile Times?" : 0 = [ 0: "Yes" 1: "No" ]
  85.     if (IntForKey(mapent, "estimate")) 
  86.     {
  87.         g_estimate = true;
  88.     }
  89.     else
  90.     {
  91.         g_estimate = false;
  92.     }
  93.     Log("%30s [ %-9s ]\n", "Estimate Compile Times", g_estimate ? "on" : "off");
  94.  
  95.     // priority(choices) : "Priority Level" : 0 = [    0 : "Normal" 1 : "High"    -1 : "Low" ]
  96.     if (!strcmp(ValueForKey(mapent, "priority"), "1"))
  97.     {
  98.         g_threadpriority = eThreadPriorityHigh;
  99.         Log("%30s [ %-9s ]\n", "Thread Priority", "high");
  100.     }
  101.     else if (!strcmp(ValueForKey(mapent, "priority"), "-1"))
  102.     {
  103.         g_threadpriority = eThreadPriorityLow;
  104.         Log("%30s [ %-9s ]\n", "Thread Priority", "low");
  105.     }
  106.  
  107.     /*
  108.     hlbsp(choices) : "HLBSP" : 0 =
  109.     [
  110.        0 : "Off" 
  111.        1 : "Normal"
  112.        2 : "Leakonly"
  113.     ]
  114.     */
  115.     iTmp = IntForKey(mapent, "hlbsp");
  116.     if (iTmp == 0)
  117.     {
  118.         Fatal(assume_TOOL_CANCEL, 
  119.             "%s flag was not checked in info_compile_parameters entity, execution of %s cancelled", g_Program, g_Program);
  120.         CheckFatal();   
  121.     }
  122.     else if (iTmp == 1)
  123.     {
  124.         g_bLeakOnly = false;
  125.     }
  126.     else if (iTmp == 2)
  127.     {
  128.         g_bLeakOnly = true;
  129.     }
  130.     Log("%30s [ %-9s ]\n", "Leakonly Mode", g_bLeakOnly ? "on" : "off"); 
  131.  
  132.     /*
  133.     nocliphull(choices) : "Generate clipping hulls" : 0 =
  134.     [
  135.         0 : "Yes"
  136.         1 : "No"
  137.     ]
  138.     */
  139.     iTmp = IntForKey(mapent, "nocliphull");
  140.     if (iTmp == 0)
  141.     {
  142.         g_noclip = false;
  143.     }
  144.     else if (iTmp == 1)
  145.     {
  146.         g_noclip = true;
  147.     }
  148.     Log("%30s [ %-9s ]\n", "Clipping Hull Generation", g_noclip ? "off" : "on");
  149.  
  150.     //////////////////
  151.     Verbose("\n");
  152. }
  153. #endif
  154.  
  155. // =====================================================================================
  156. //  NewFaceFromFace
  157. //      Duplicates the non point information of a face, used by SplitFace and MergeFace.
  158. // =====================================================================================
  159. face_t*         NewFaceFromFace(const face_t* const in)
  160. {
  161.     face_t*         newf;
  162.  
  163.     newf = AllocFace();
  164.  
  165.     newf->planenum = in->planenum;
  166.     newf->texturenum = in->texturenum;
  167.     newf->original = in->original;
  168.     newf->contents = in->contents;
  169.  
  170.     return newf;
  171. }
  172.  
  173. // =====================================================================================
  174. //  SplitFaceTmp
  175. //      blah
  176. // =====================================================================================
  177. static void     SplitFaceTmp(face_t* in, const dplane_t* const split, face_t** front, face_t** back)
  178. {
  179.     vec_t           dists[MAXEDGES + 1];
  180.     int             sides[MAXEDGES + 1];
  181.     int             counts[3];
  182.     vec_t           dot;
  183.     int             i;
  184.     int             j;
  185.     face_t*         newf;
  186.     face_t*         new2;
  187.     vec_t*          p1;
  188.     vec_t*          p2;
  189.     vec3_t          mid;
  190.  
  191.     if (in->numpoints < 0)
  192.     {
  193.         Error("SplitFace: freed face");
  194.     }
  195.     counts[0] = counts[1] = counts[2] = 0;
  196.  
  197.     // determine sides for each point
  198.     for (i = 0; i < in->numpoints; i++)
  199.     {
  200.         dot = DotProduct(in->pts[i], split->normal);
  201.         dot -= split->dist;
  202.         dists[i] = dot;
  203.         if (dot > ON_EPSILON)
  204.         {
  205.             sides[i] = SIDE_FRONT;
  206.         }
  207.         else if (dot < -ON_EPSILON)
  208.         {
  209.             sides[i] = SIDE_BACK;
  210.         }
  211.         else
  212.         {
  213.             sides[i] = SIDE_ON;
  214.         }
  215.         counts[sides[i]]++;
  216.     }
  217.     sides[i] = sides[0];
  218.     dists[i] = dists[0];
  219.  
  220.     if (!counts[0])
  221.     {
  222.         *front = NULL;
  223.         *back = in;
  224.         return;
  225.     }
  226.     if (!counts[1])
  227.     {
  228.         *front = in;
  229.         *back = NULL;
  230.         return;
  231.     }
  232.  
  233.     *back = newf = NewFaceFromFace(in);
  234.     *front = new2 = NewFaceFromFace(in);
  235.  
  236.     // distribute the points and generate splits
  237.  
  238.     for (i = 0; i < in->numpoints; i++)
  239.     {
  240.         if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
  241.         {
  242.             Error("SplitFace: numpoints > MAXEDGES");
  243.         }
  244.  
  245.         p1 = in->pts[i];
  246.  
  247.         if (sides[i] == SIDE_ON)
  248.         {
  249.             VectorCopy(p1, newf->pts[newf->numpoints]);
  250.             newf->numpoints++;
  251.             VectorCopy(p1, new2->pts[new2->numpoints]);
  252.             new2->numpoints++;
  253.             continue;
  254.         }
  255.  
  256.         if (sides[i] == SIDE_FRONT)
  257.         {
  258.             VectorCopy(p1, new2->pts[new2->numpoints]);
  259.             new2->numpoints++;
  260.         }
  261.         else
  262.         {
  263.             VectorCopy(p1, newf->pts[newf->numpoints]);
  264.             newf->numpoints++;
  265.         }
  266.  
  267.         if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i])
  268.         {
  269.             continue;
  270.         }
  271.  
  272.         // generate a split point
  273.         p2 = in->pts[(i + 1) % in->numpoints];
  274.  
  275.         dot = dists[i] / (dists[i] - dists[i + 1]);
  276.         for (j = 0; j < 3; j++)
  277.         {                                                  // avoid round off error when possible
  278.             if (split->normal[j] == 1)
  279.             {
  280.                 mid[j] = split->dist;
  281.             }
  282.             else if (split->normal[j] == -1)
  283.             {
  284.                 mid[j] = -split->dist;
  285.             }
  286.             else
  287.             {
  288.                 mid[j] = p1[j] + dot * (p2[j] - p1[j]);
  289.             }
  290.         }
  291.  
  292.         VectorCopy(mid, newf->pts[newf->numpoints]);
  293.         newf->numpoints++;
  294.         VectorCopy(mid, new2->pts[new2->numpoints]);
  295.         new2->numpoints++;
  296.     }
  297.  
  298.     if (newf->numpoints > MAXEDGES || new2->numpoints > MAXEDGES)
  299.     {
  300.         Error("SplitFace: numpoints > MAXEDGES");
  301.     }
  302. }
  303.  
  304. // =====================================================================================
  305. //  SplitFace
  306. //      blah
  307. // =====================================================================================
  308. void            SplitFace(face_t* in, const dplane_t* const split, face_t** front, face_t** back)
  309. {
  310.     SplitFaceTmp(in, split, front, back);
  311.  
  312.     // free the original face now that is is represented by the fragments
  313.     if (*front && *back)
  314.     {
  315.         FreeFace(in);
  316.     }
  317. }
  318.  
  319. // =====================================================================================
  320. //  AllocFace
  321. // =====================================================================================
  322. face_t*         AllocFace()
  323. {
  324.     face_t*         f;
  325.  
  326.     f = (face_t*)malloc(sizeof(face_t));
  327.     memset(f, 0, sizeof(face_t));
  328.  
  329.     f->planenum = -1;
  330.  
  331.     return f;
  332. }
  333.  
  334. // =====================================================================================
  335. //  FreeFace
  336. // =====================================================================================
  337. void            FreeFace(face_t* f)
  338. {
  339.     free(f);
  340. }
  341.  
  342. // =====================================================================================
  343. //  AllocSurface
  344. // =====================================================================================
  345. surface_t*      AllocSurface()
  346. {
  347.     surface_t*      s;
  348.  
  349.     s = (surface_t*)malloc(sizeof(surface_t));
  350.     memset(s, 0, sizeof(surface_t));
  351.  
  352.     return s;
  353. }
  354.  
  355. // =====================================================================================
  356. //  FreeSurface
  357. // =====================================================================================
  358. void            FreeSurface(surface_t* s)
  359. {
  360.     free(s);
  361. }
  362.  
  363. // =====================================================================================
  364. //  AllocPortal
  365. // =====================================================================================
  366. portal_t*       AllocPortal()
  367. {
  368.     portal_t*       p;
  369.  
  370.     p = (portal_t*)malloc(sizeof(portal_t));
  371.     memset(p, 0, sizeof(portal_t));
  372.  
  373.     return p;
  374. }
  375.  
  376. // =====================================================================================
  377. //  FreePortal
  378. // =====================================================================================
  379. void            FreePortal(portal_t* p) // consider: inline
  380. {
  381.     free(p);
  382. }
  383.  
  384.  
  385. // =====================================================================================
  386. //  AllocNode
  387. //      blah
  388. // =====================================================================================
  389. node_t*         AllocNode()
  390. {
  391.     node_t*         n;
  392.  
  393.     n = (node_t*)malloc(sizeof(node_t));
  394.     memset(n, 0, sizeof(node_t));
  395.  
  396.     return n;
  397. }
  398.  
  399. // =====================================================================================
  400. //  AddPointToBounds
  401. // =====================================================================================
  402. void            AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs)
  403. {
  404.     int             i;
  405.     vec_t           val;
  406.  
  407.     for (i = 0; i < 3; i++)
  408.     {
  409.         val = v[i];
  410.         if (val < mins[i])
  411.         {
  412.             mins[i] = val;
  413.         }
  414.         if (val > maxs[i])
  415.         {
  416.             maxs[i] = val;
  417.         }
  418.     }
  419. }
  420.  
  421. // =====================================================================================
  422. //  AddFaceToBounds
  423. // =====================================================================================
  424. static void     AddFaceToBounds(const face_t* const f, vec3_t mins, vec3_t maxs)
  425. {
  426.     int             i;
  427.  
  428.     for (i = 0; i < f->numpoints; i++)
  429.     {
  430.         AddPointToBounds(f->pts[i], mins, maxs);
  431.     }
  432. }
  433.  
  434. // =====================================================================================
  435. //  ClearBounds
  436. // =====================================================================================
  437. static void     ClearBounds(vec3_t mins, vec3_t maxs)
  438. {
  439.     mins[0] = mins[1] = mins[2] = 99999;
  440.     maxs[0] = maxs[1] = maxs[2] = -99999;
  441. }
  442.  
  443. // =====================================================================================
  444. //  SurflistFromValidFaces
  445. //      blah
  446. // =====================================================================================
  447. static surfchain_t* SurflistFromValidFaces()
  448. {
  449.     surface_t*      n;
  450.     int             i;
  451.     face_t*         f;
  452.     face_t*         next;
  453.     surfchain_t*    sc;
  454.  
  455.     sc = (surfchain_t*)malloc(sizeof(*sc));
  456.     ClearBounds(sc->mins, sc->maxs);
  457.     sc->surfaces = NULL;
  458.  
  459.     // grab planes from both sides
  460.     for (i = 0; i < g_numplanes; i += 2)
  461.     {
  462.         if (!validfaces[i] && !validfaces[i + 1])
  463.         {
  464.             continue;
  465.         }
  466.         n = AllocSurface();
  467.         n->next = sc->surfaces;
  468.         sc->surfaces = n;
  469.         ClearBounds(n->mins, n->maxs);
  470.         n->planenum = i;
  471.  
  472.         n->faces = NULL;
  473.         for (f = validfaces[i]; f; f = next)
  474.         {
  475.             next = f->next;
  476.             f->next = n->faces;
  477.             n->faces = f;
  478.             AddFaceToBounds(f, n->mins, n->maxs);
  479.         }
  480.         for (f = validfaces[i + 1]; f; f = next)
  481.         {
  482.             next = f->next;
  483.             f->next = n->faces;
  484.             n->faces = f;
  485.             AddFaceToBounds(f, n->mins, n->maxs);
  486.         }
  487.  
  488.         AddPointToBounds(n->mins, sc->mins, sc->maxs);
  489.         AddPointToBounds(n->maxs, sc->mins, sc->maxs);
  490.  
  491.         validfaces[i] = NULL;
  492.         validfaces[i + 1] = NULL;
  493.     }
  494.  
  495.     // merge all possible polygons
  496.  
  497.     MergeAll(sc->surfaces);
  498.  
  499.     return sc;
  500. }
  501.  
  502. #ifdef ZHLT_NULLTEX// AJM
  503. // =====================================================================================
  504. //  CheckFaceForNull
  505. //      Returns true if the passed face is facetype null 
  506. // =====================================================================================
  507. bool            CheckFaceForNull(const face_t* const f)
  508. {
  509.     // null faces are only of facetype face_null if we are using null texture stripping
  510.     if (g_bUseNullTex) 
  511.     {
  512.         texinfo_t*      info;
  513.         miptex_t*       miptex;
  514.         int             ofs;
  515.  
  516.         info = &g_texinfo[f->texturenum];
  517.         ofs = ((dmiptexlump_t*)g_dtexdata)->dataofs[info->miptex];
  518.         miptex = (miptex_t*)(&g_dtexdata[ofs]);
  519.  
  520.         if (!strcasecmp(miptex->name, "null")) 
  521.             return true;
  522.         else
  523.             return false;
  524.     }
  525.     else // otherwise, under normal cases, null textured faces should be facetype face_normal
  526.     {
  527.         return false;
  528.     }
  529. }
  530. #endif
  531.  
  532. #ifdef ZHLT_DETAIL
  533. // =====================================================================================
  534. //  CheckFaceForDetail
  535. //      Returns true if the passed face is part of a detail brush
  536. // =====================================================================================
  537. bool            CheckFaceForDetail(const face_t* const f)
  538. {
  539.     if (f->contents == CONTENTS_DETAIL)
  540.     {
  541.         //Log("CheckFaceForDetail:: got a detail face");
  542.         return true;
  543.     }
  544.  
  545.     return false;
  546. }
  547. #endif
  548.  
  549. // =====================================================================================
  550. //  CheckFaceForHint
  551. //      Returns true if the passed face is facetype hint
  552. // =====================================================================================
  553. bool            CheckFaceForHint(const face_t* const f)
  554. {
  555.     texinfo_t*      info;
  556.     miptex_t*       miptex;
  557.     int             ofs;
  558.  
  559.     info = &g_texinfo[f->texturenum];
  560.     ofs = ((dmiptexlump_t *)g_dtexdata)->dataofs[info->miptex];
  561.     miptex = (miptex_t *)(&g_dtexdata[ofs]);
  562.  
  563.     if (!strcasecmp(miptex->name, "hint"))
  564.     {
  565.         return true;
  566.     }
  567.     else
  568.     {
  569.         return false;
  570.     }
  571. }
  572.  
  573. // =====================================================================================
  574. //  CheckFaceForSkipt
  575. //      Returns true if the passed face is facetype skip
  576. // =====================================================================================
  577. bool            CheckFaceForSkip(const face_t* const f)
  578. {
  579.     texinfo_t*      info;
  580.     miptex_t*       miptex;
  581.     int             ofs;
  582.  
  583.     info = &g_texinfo[f->texturenum];
  584.     ofs = ((dmiptexlump_t*)g_dtexdata)->dataofs[info->miptex];
  585.     miptex = (miptex_t*)(&g_dtexdata[ofs]);
  586.  
  587.     if (!strcasecmp(miptex->name, "skip"))
  588.     {
  589.         return true;
  590.     }
  591.     else
  592.     {
  593.         return false;
  594.     }
  595. }
  596.  
  597. // =====================================================================================
  598. //  SetFaceType
  599. // =====================================================================================
  600. static          facestyle_e SetFaceType(face_t* f)
  601. {
  602.     if (CheckFaceForHint(f))
  603.     {
  604.         f->facestyle = face_hint;
  605.     }
  606.     else if (CheckFaceForSkip(f))
  607.     {
  608.         f->facestyle = face_skip;
  609.     }
  610. #ifdef ZHLT_NULLTEX         // AJM
  611.     else if (CheckFaceForNull(f))
  612.     {
  613.         f->facestyle = face_null;
  614.     }
  615. #endif
  616. #ifdef ZHLT_DETAIL
  617.     else if (CheckFaceForDetail(f))
  618.     {
  619.         //Log("SetFaceType::detail face\n");
  620.         f->facestyle = face_detail;
  621.     }
  622. #endif
  623.     else
  624.     {
  625.         f->facestyle = face_normal;
  626.     }
  627.     return f->facestyle;
  628. }
  629.  
  630. // =====================================================================================
  631. //  ReadSurfs
  632. // =====================================================================================
  633. static surfchain_t* ReadSurfs(FILE* file)
  634. {
  635.     int             r;
  636.     int             planenum, g_texinfo, contents, numpoints;
  637.     face_t*         f;
  638.     int             i;
  639.     double          v[3];
  640.     int             line = 0;
  641.  
  642.     // read in the polygons
  643.     while (1)
  644.     {
  645.         line++;
  646.         r = fscanf(file, "%i %i %i %i\n", &planenum, &g_texinfo, &contents, &numpoints);
  647.         if (r == 0 || r == -1)
  648.         {
  649.             return NULL;
  650.         }
  651.         if (planenum == -1)                                // end of model
  652.         {
  653.             break;
  654.         }
  655.         if (r != 4)
  656.         {
  657.             Error("ReadSurfs (line %i): scanf failure", line);
  658.         }
  659.         if (numpoints > MAXPOINTS)
  660.         {
  661.             Error("ReadSurfs (line %i): %i > MAXPOINTS\nThis is caused by a face with too many verticies (typically found on end-caps of high-poly cylinders)\n", line, numpoints);
  662.         }
  663.         if (planenum > g_numplanes)
  664.         {
  665.             Error("ReadSurfs (line %i): %i > g_numplanes\n", line, planenum);
  666.         }
  667.         if (g_texinfo > g_numtexinfo)
  668.         {
  669.             Error("ReadSurfs (line %i): %i > g_numtexinfo", line, g_texinfo);
  670.         }
  671.  
  672.         if (!strcasecmp(GetTextureByNumber(g_texinfo), "skip"))
  673.         {
  674.             Verbose("ReadSurfs (line %i): skipping a surface", line);
  675.  
  676.             for (i = 0; i < numpoints; i++)
  677.             {
  678.                 line++;
  679.                 //Verbose("skipping line %d", line);
  680.                 r = fscanf(file, "%lf %lf %lf\n", &v[0], &v[1], &v[2]);
  681.                 if (r != 3)
  682.                 {
  683.                     Error("::ReadSurfs (face_skip), fscanf of points failed at line %i", line);
  684.                 }
  685.             }
  686.             fscanf(file, "\n");
  687.             continue;
  688.         }
  689.  
  690.         f = AllocFace();
  691.         f->planenum = planenum;
  692.         f->texturenum = g_texinfo;
  693.         f->contents = contents;
  694.         f->numpoints = numpoints;
  695.         f->next = validfaces[planenum];
  696.         validfaces[planenum] = f;
  697.  
  698.         SetFaceType(f);
  699.  
  700.         for (i = 0; i < f->numpoints; i++)
  701.         {
  702.             line++;
  703.             r = fscanf(file, "%lf %lf %lf\n", &v[0], &v[1], &v[2]);
  704.             if (r != 3)
  705.             {
  706.                 Error("::ReadSurfs (face_normal), fscanf of points failed at line %i", line);
  707.             }
  708.             VectorCopy(v, f->pts[i]);
  709.         }
  710.         fscanf(file, "\n");
  711.     }
  712.  
  713.     return SurflistFromValidFaces();
  714. }
  715.  
  716.  
  717. #ifdef HLBSP_THREADS// AJM
  718. // =====================================================================================
  719. //  ProcessModelThreaded
  720. // time to compl
  721. // =====================================================================================
  722. void            ProcessModel(int modelnum)
  723. {
  724.     surfchain_t*    surfs;
  725.     node_t*         nodes;
  726.     dmodel_t*       model;
  727.     int             startleafs;
  728.  
  729.     surfs = ReadSurfs(polyfiles[0]);
  730.  
  731.     if (!surfs)
  732.         return; // all models are done
  733.  
  734.     hlassume(g_nummodels < MAX_MAP_MODELS, assume_MAX_MAP_MODELS);
  735.  
  736.     startleafs = g_numleafs;
  737.     int modnum = g_nummodels;
  738.     model = &g_dmodels[modnum];
  739.     g_nummodels++;
  740.  
  741. //    Log("ProcessModel: %i (%i f)\n", modnum, model->numfaces);
  742.  
  743.     VectorCopy(surfs->mins, model->mins);
  744.     VectorCopy(surfs->maxs, model->maxs);
  745.  
  746.     // SolidBSP generates a node tree
  747.     nodes = SolidBSP(surfs);
  748.  
  749.     // build all the portals in the bsp tree
  750.     // some portals are solid polygons, and some are paths to other leafs
  751.     if (g_nummodels == 1 && !g_nofill)                       // assume non-world bmodels are simple
  752.     {
  753.         nodes = FillOutside(nodes, (g_bLeaked != true), 0);                  // make a leakfile if bad
  754.     }
  755.  
  756.     FreePortals(nodes);
  757.  
  758.     // fix tjunctions
  759.     tjunc(nodes);
  760.  
  761.     MakeFaceEdges();
  762.  
  763.     // emit the faces for the bsp file
  764.     model->headnode[0] = g_numnodes;
  765.     model->firstface = g_numfaces;
  766.     WriteDrawNodes(nodes);
  767.     model->numfaces = g_numfaces - model->firstface;;
  768.     model->visleafs = g_numleafs - startleafs;
  769.  
  770.     if (g_noclip)
  771.     {
  772.         return true;
  773.     }
  774.  
  775.     // the clipping hulls are simpler
  776.     for (g_hullnum = 1; g_hullnum < NUM_HULLS; g_hullnum++)
  777.     {
  778.         surfs = ReadSurfs(polyfiles[g_hullnum]);
  779.         nodes = SolidBSP(surfs);
  780.         if (g_nummodels == 1 && !g_nofill)                   // assume non-world bmodels are simple
  781.         {
  782.             nodes = FillOutside(nodes, (g_bLeaked != true), g_hullnum);
  783.         }
  784.         FreePortals(nodes);
  785.         model->headnode[g_hullnum] = g_numclipnodes;
  786.         WriteClipNodes(nodes);
  787.     }
  788.  
  789.     return true;
  790. }
  791.  
  792. #else
  793. // =====================================================================================
  794. //  ProcessModel
  795. // =====================================================================================
  796. static bool     ProcessModel()
  797. {
  798.     surfchain_t*    surfs;
  799.     node_t*         nodes;
  800.     dmodel_t*       model;
  801.     int             startleafs;
  802.  
  803.     surfs = ReadSurfs(polyfiles[0]);
  804.  
  805.     if (!surfs)
  806.         return false;                                      // all models are done
  807.  
  808.     hlassume(g_nummodels < MAX_MAP_MODELS, assume_MAX_MAP_MODELS);
  809.  
  810.     startleafs = g_numleafs;
  811.     int modnum = g_nummodels;
  812.     model = &g_dmodels[modnum];
  813.     g_nummodels++;
  814.  
  815. //    Log("ProcessModel: %i (%i f)\n", modnum, model->numfaces);
  816.  
  817.     VectorCopy(surfs->mins, model->mins);
  818.     VectorCopy(surfs->maxs, model->maxs);
  819.  
  820.     // SolidBSP generates a node tree
  821.     nodes = SolidBSP(surfs);
  822.  
  823.     // build all the portals in the bsp tree
  824.     // some portals are solid polygons, and some are paths to other leafs
  825.     if (g_nummodels == 1 && !g_nofill)                       // assume non-world bmodels are simple
  826.     {
  827.         nodes = FillOutside(nodes, (g_bLeaked != true), 0);                  // make a leakfile if bad
  828.     }
  829.  
  830.     FreePortals(nodes);
  831.  
  832.     // fix tjunctions
  833.     tjunc(nodes);
  834.  
  835.     MakeFaceEdges();
  836.  
  837.     // emit the faces for the bsp file
  838.     model->headnode[0] = g_numnodes;
  839.     model->firstface = g_numfaces;
  840.     WriteDrawNodes(nodes);
  841.     model->numfaces = g_numfaces - model->firstface;;
  842.     model->visleafs = g_numleafs - startleafs;
  843.  
  844.     if (g_noclip)
  845.     {
  846.         return true;
  847.     }
  848.  
  849.     // the clipping hulls are simpler
  850.     for (g_hullnum = 1; g_hullnum < NUM_HULLS; g_hullnum++)
  851.     {
  852.         surfs = ReadSurfs(polyfiles[g_hullnum]);
  853.         nodes = SolidBSP(surfs);
  854.         if (g_nummodels == 1 && !g_nofill)                   // assume non-world bmodels are simple
  855.         {
  856.             nodes = FillOutside(nodes, (g_bLeaked != true), g_hullnum);
  857.         }
  858.         FreePortals(nodes);
  859.         model->headnode[g_hullnum] = g_numclipnodes;
  860.         WriteClipNodes(nodes);
  861.     }
  862.  
  863.     return true;
  864. }
  865. #endif
  866.  
  867. // =====================================================================================
  868. //  Usage
  869. // =====================================================================================
  870. static void     Usage()
  871. {
  872.     Banner();
  873.  
  874.     Log("\n-= %s Options =-\n\n", g_Program);
  875.     Log("    -leakonly      : Run BSP only enough to check for LEAKs\n");
  876.     Log("    -subdivide #   : Sets the face subdivide size\n");
  877.     Log("    -maxnodesize # : Sets the maximum portal node size\n\n");
  878.     Log("    -notjunc       : Don't break edges on t-junctions     (not for final runs)\n");
  879.     Log("    -noclip        : Don't process the clipping hull      (not for final runs)\n");
  880.     Log("    -nofill        : Don't fill outside (will mask LEAKs) (not for final runs)\n\n");
  881.     Log("    -texdata #     : Alter maximum texture memory limit (in kb)\n");
  882.     Log("    -chart         : display bsp statitics\n");
  883.     Log("    -low | -high   : run program an altered priority level\n");
  884.     Log("    -nolog         : don't generate the compile logfiles\n");
  885.     Log("    -threads #     : manually specify the number of threads to run\n");
  886. #ifdef SYSTEM_WIN32
  887.     Log("    -estimate      : display estimated time during compile\n");
  888. #endif
  889. #ifdef ZHLT_PROGRESSFILE // AJM
  890.     Log("    -progressfile path  : specify the path to a file for progress estimate output\n");
  891. #endif
  892. #ifdef SYSTEM_POSIX
  893.     Log("    -noestimate    : do not display continuous compile time estimates\n");
  894. #endif
  895.  
  896. #ifdef ZHLT_NULLTEX         // AJM
  897.     Log("    -nonulltex     : Don't strip NULL faces\n");
  898. #endif
  899.  
  900. #ifdef ZHLT_DETAIL // AJM
  901.     Log("    -nodetail      : don't handle detail brushes\n");
  902. #endif
  903.  
  904.     Log("    -verbose       : compile with verbose messages\n");
  905.     Log("    -noinfo        : Do not show tool configuration information\n");
  906.     Log("    -dev #         : compile with developer message\n\n");
  907.     Log("    mapfile        : The mapfile to compile\n\n");
  908.  
  909.     exit(1);
  910. }
  911.  
  912. // =====================================================================================
  913. //  Settings
  914. // =====================================================================================
  915. static void     Settings()
  916. {
  917.     char*           tmp;
  918.  
  919.     if (!g_info)
  920.         return;
  921.  
  922.     Log("\nCurrent %s Settings\n", g_Program);
  923.     Log("Name               |  Setting  |  Default\n" "-------------------|-----------|-------------------------\n");
  924.  
  925.     // ZHLT Common Settings
  926.     if (DEFAULT_NUMTHREADS == -1)
  927.     {
  928.         Log("threads             [ %7d ] [  Varies ]\n", g_numthreads);
  929.     }
  930.     else
  931.     {
  932.         Log("threads             [ %7d ] [ %7d ]\n", g_numthreads, DEFAULT_NUMTHREADS);
  933.     }
  934.  
  935.     Log("verbose             [ %7s ] [ %7s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off");
  936.     Log("log                 [ %7s ] [ %7s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off");
  937.     Log("developer           [ %7d ] [ %7d ]\n", g_developer, DEFAULT_DEVELOPER);
  938.     Log("chart               [ %7s ] [ %7s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
  939.     Log("estimate            [ %7s ] [ %7s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off");
  940.     Log("max texture memory  [ %7d ] [ %7d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
  941.  
  942.     switch (g_threadpriority)
  943.     {
  944.     case eThreadPriorityNormal:
  945.     default:
  946.         tmp = "Normal";
  947.         break;
  948.     case eThreadPriorityLow:
  949.         tmp = "Low";
  950.         break;
  951.     case eThreadPriorityHigh:
  952.         tmp = "High";
  953.         break;
  954.     }
  955.     Log("priority            [ %7s ] [ %7s ]\n", tmp, "Normal");
  956.     Log("\n");
  957.  
  958.     // HLBSP Specific Settings
  959.     Log("noclip              [ %7s ] [ %7s ]\n", g_noclip ? "on" : "off", DEFAULT_NOCLIP ? "on" : "off");
  960.     Log("nofill              [ %7s ] [ %7s ]\n", g_nofill ? "on" : "off", DEFAULT_NOFILL ? "on" : "off");
  961. #ifdef ZHLT_NULLTEX // AJM
  962.     Log("null tex. stripping [ %7s ] [ %7s ]\n", g_bUseNullTex ? "on" : "off", DEFAULT_NULLTEX ? "on" : "off" );
  963. #endif
  964. #ifdef ZHLT_DETAIL // AJM
  965.     Log("detail brushes      [ %7s ] [ %7s ]\n", g_bDetailBrushes ? "on" : "off", DEFAULT_DETAIL ? "on" : "off" );
  966. #endif
  967.     Log("notjunc             [ %7s ] [ %7s ]\n", g_notjunc ? "on" : "off", DEFAULT_NOTJUNC ? "on" : "off");
  968.     Log("subdivide size      [ %7d ] [ %7d ] (Min %d) (Max %d)\n",
  969.         g_subdivide_size, DEFAULT_SUBDIVIDE_SIZE, MIN_SUBDIVIDE_SIZE, MAX_SUBDIVIDE_SIZE);
  970.     Log("max node size       [ %7d ] [ %7d ] (Min %d) (Max %d)\n",
  971.         g_maxnode_size, DEFAULT_MAXNODE_SIZE, MIN_MAXNODE_SIZE, MAX_MAXNODE_SIZE);
  972.  
  973.     Log("\n\n");
  974. }
  975.  
  976. // =====================================================================================
  977. //  ProcessFile
  978. // =====================================================================================
  979. static void     ProcessFile(const char* const filename)
  980. {
  981.     int             i;
  982.     char            name[_MAX_PATH];
  983.  
  984.     // delete existing files
  985.     safe_snprintf(g_portfilename, _MAX_PATH, "%s.prt", filename);  
  986.     unlink(g_portfilename);
  987.  
  988.     safe_snprintf(g_pointfilename, _MAX_PATH, "%s.pts", filename);
  989.     unlink(g_pointfilename);
  990.  
  991.     safe_snprintf(g_linefilename, _MAX_PATH, "%s.lin", filename);
  992.     unlink(g_linefilename);
  993.  
  994.     // open the hull files
  995.     for (i = 0; i < NUM_HULLS; i++)
  996.     {
  997.                    //mapname.p[0-3]
  998.         sprintf(name, "%s.p%i", filename, i);
  999.         polyfiles[i] = fopen(name, "r");
  1000.  
  1001.         if (!polyfiles[i])
  1002.             Error("Can't open %s", name);
  1003.     }
  1004.  
  1005.     // load the output of csg
  1006.     safe_snprintf(g_bspfilename, _MAX_PATH, "%s.bsp", filename);
  1007.     LoadBSPFile(g_bspfilename);
  1008.     ParseEntities();
  1009.  
  1010.     Settings(); // AJM: moved here due to info_compile_parameters entity
  1011.  
  1012.     // init the tables to be shared by all models
  1013.     BeginBSPFile();
  1014.  
  1015. #ifdef HLBSP_THREADS // AJM
  1016.     NamedRunThreadsOnIndividual(nummodels, g_estimate, ProcessModel);
  1017. #else
  1018.     // process each model individually
  1019.     while (ProcessModel())
  1020.         ;
  1021. #endif
  1022.  
  1023.     // write the updated bsp file out
  1024.     FinishBSPFile();
  1025. }
  1026.  
  1027. // =====================================================================================
  1028. //  main
  1029. // =====================================================================================
  1030. int             main(const int argc, char** argv)
  1031. {
  1032.     int             i;
  1033.     double          start, end;
  1034.     const char*     mapname_from_arg = NULL;
  1035.  
  1036.     g_Program = "hlbsp";
  1037.  
  1038.     // if we dont have any command line argvars, print out usage and die
  1039.     if (argc == 1)
  1040.         Usage();
  1041.  
  1042.     // check command line args
  1043.     for (i = 1; i < argc; i++)
  1044.     {
  1045.         if (!strcasecmp(argv[i], "-threads"))
  1046.         {
  1047.             if (i < argc)
  1048.             {
  1049.                 int             g_numthreads = atoi(argv[++i]);
  1050.  
  1051.                 if (g_numthreads < 1)
  1052.                 {
  1053.                     Log("Expected value of at least 1 for '-threads'\n");
  1054.                     Usage();
  1055.                 }
  1056.             }
  1057.             else
  1058.             {
  1059.                 Usage();
  1060.             }
  1061.         }
  1062.         else if (!strcasecmp(argv[i], "-notjunc"))
  1063.         {
  1064.             g_notjunc = true;
  1065.         }
  1066.         else if (!strcasecmp(argv[i], "-noclip"))
  1067.         {
  1068.             g_noclip = true;
  1069.         }
  1070.         else if (!strcasecmp(argv[i], "-nofill"))
  1071.         {
  1072.             g_nofill = true;
  1073.         }
  1074.  
  1075. #ifdef SYSTEM_WIN32
  1076.         else if (!strcasecmp(argv[i], "-estimate"))
  1077.         {
  1078.             g_estimate = true;
  1079.         }
  1080. #endif
  1081.  
  1082. #ifdef SYSTEM_POSIX
  1083.         else if (!strcasecmp(argv[i], "-noestimate"))
  1084.         {
  1085.             g_estimate = false;
  1086.         }
  1087. #endif
  1088.  
  1089. #ifdef ZHLT_NETVIS
  1090.         else if (!strcasecmp(argv[i], "-client"))
  1091.         {
  1092.             if (i < argc)
  1093.             {
  1094.                 g_clientid = atoi(argv[++i]);
  1095.             }
  1096.             else
  1097.             {
  1098.                 Usage();
  1099.             }
  1100.         }
  1101. #endif
  1102.  
  1103. #ifdef ZHLT_PROGRESSFILE // AJM
  1104.         else if (!strcasecmp(argv[i], "-progressfile"))
  1105.         {
  1106.             if (i < argc)
  1107.             {
  1108.                 g_progressfile = argv[++i];
  1109.             }
  1110.             else
  1111.             {
  1112.                 Log("Error: -progressfile: expected path to progress file following parameter\n");
  1113.                 Usage();
  1114.             }
  1115.         }
  1116. #endif
  1117.  
  1118.         else if (!strcasecmp(argv[i], "-dev"))
  1119.         {
  1120.             if (i < argc)
  1121.             {
  1122.                 g_developer = (developer_level_t)atoi(argv[++i]);
  1123.             }
  1124.             else
  1125.             {
  1126.                 Usage();
  1127.             }
  1128.         }
  1129.         else if (!strcasecmp(argv[i], "-verbose"))
  1130.         {
  1131.             g_verbose = true;
  1132.         }
  1133.         else if (!strcasecmp(argv[i], "-noinfo"))
  1134.         {
  1135.             g_info = false;
  1136.         }
  1137.         else if (!strcasecmp(argv[i], "-leakonly"))
  1138.         {
  1139.             g_bLeakOnly = true;
  1140.         }
  1141.         else if (!strcasecmp(argv[i], "-chart"))
  1142.         {
  1143.             g_chart = true;
  1144.         }
  1145.         else if (!strcasecmp(argv[i], "-low"))
  1146.         {
  1147.             g_threadpriority = eThreadPriorityLow;
  1148.         }
  1149.         else if (!strcasecmp(argv[i], "-high"))
  1150.         {
  1151.             g_threadpriority = eThreadPriorityHigh;
  1152.         }
  1153.         else if (!strcasecmp(argv[i], "-nolog"))
  1154.         {
  1155.             g_log = false;
  1156.         }
  1157.  
  1158. #ifdef ZHLT_NULLTEX // AJM
  1159.         else if (!strcasecmp(argv[i], "-nonulltex"))
  1160.         {
  1161.             g_bUseNullTex = false;
  1162.         }
  1163. #endif
  1164.  
  1165. #ifdef ZHLT_DETAIL // AJM
  1166.         else if (!strcasecmp(argv[i], "-nodetail"))
  1167.         {
  1168.             g_bDetailBrushes = false;
  1169.         }
  1170. #endif
  1171.  
  1172.         else if (!strcasecmp(argv[i], "-subdivide"))
  1173.         {
  1174.             if (i < argc)
  1175.             {
  1176.                 g_subdivide_size = atoi(argv[++i]);
  1177.                 if (g_subdivide_size > MAX_SUBDIVIDE_SIZE)
  1178.                 {
  1179.                     Warning
  1180.                         ("Maximum value for subdivide size is %i, '-subdivide %i' ignored",
  1181.                          MAX_SUBDIVIDE_SIZE, g_subdivide_size);
  1182.                     g_subdivide_size = MAX_SUBDIVIDE_SIZE;
  1183.                 }
  1184.                 else if (g_subdivide_size < MIN_SUBDIVIDE_SIZE)
  1185.                 {
  1186.                     Warning
  1187.                         ("Mininum value for subdivide size is %i, '-subdivide %i' ignored",
  1188.                          MIN_SUBDIVIDE_SIZE, g_subdivide_size);
  1189.                     g_subdivide_size = MAX_SUBDIVIDE_SIZE;
  1190.                 }
  1191.             }
  1192.             else
  1193.             {
  1194.                 Usage();
  1195.             }
  1196.         }
  1197.         else if (!strcasecmp(argv[i], "-maxnodesize"))
  1198.         {
  1199.             if (i < argc)
  1200.             {
  1201.                 g_maxnode_size = atoi(argv[++i]);
  1202.                 if (g_maxnode_size > MAX_MAXNODE_SIZE)
  1203.                 {
  1204.                     Warning
  1205.                         ("Maximum value for max node size is %i, '-maxnodesize %i' ignored",
  1206.                          MAX_MAXNODE_SIZE, g_maxnode_size);
  1207.                     g_maxnode_size = MAX_MAXNODE_SIZE;
  1208.                 }
  1209.                 else if (g_maxnode_size < MIN_MAXNODE_SIZE)
  1210.                 {
  1211.                     Warning
  1212.                         ("Mininimum value for max node size is %i, '-maxnodesize %i' ignored",
  1213.                          MIN_MAXNODE_SIZE, g_maxnode_size);
  1214.                     g_maxnode_size = MAX_MAXNODE_SIZE;
  1215.                 }
  1216.             }
  1217.             else
  1218.             {
  1219.                 Usage();
  1220.             }
  1221.         }
  1222.         else if (!strcasecmp(argv[i], "-texdata"))
  1223.         {
  1224.             if (i < argc)
  1225.             {
  1226.                 int             x = atoi(argv[++i]) * 1024;
  1227.  
  1228.                 if (x > g_max_map_miptex)
  1229.                 {
  1230.                     g_max_map_miptex = x;
  1231.                 }
  1232.             }
  1233.             else
  1234.             {
  1235.                 Usage();
  1236.             }
  1237.         }
  1238.         else if (argv[i][0] == '-')
  1239.         {
  1240.             Log("Unknown option \"%s\"\n", argv[i]);
  1241.             Usage();
  1242.         }
  1243.         else if (!mapname_from_arg)
  1244.         {
  1245.             mapname_from_arg = argv[i];
  1246.         }
  1247.         else
  1248.         {
  1249.             Log("Unknown option \"%s\"\n", argv[i]);
  1250.             Usage();
  1251.         }
  1252.     }
  1253.  
  1254.     if (!mapname_from_arg)
  1255.     {
  1256.         Log("No mapfile specified\n");
  1257.         Usage();
  1258.     }
  1259.  
  1260.     safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH);
  1261.     FlipSlashes(g_Mapname);
  1262.     StripExtension(g_Mapname);
  1263.     OpenLog(g_clientid);
  1264.     atexit(CloseLog);
  1265.     ThreadSetDefault();
  1266.     ThreadSetPriority(g_threadpriority);
  1267.     LogStart(argc, argv);
  1268.  
  1269.     CheckForErrorLog();
  1270.  
  1271.     dtexdata_init();
  1272.     atexit(dtexdata_free);
  1273.     //Settings();
  1274.     // END INIT
  1275.  
  1276.     // Load the .void files for allowable entities in the void
  1277.     {
  1278.         char            g_source[_MAX_PATH];
  1279.         char            strSystemEntitiesVoidFile[_MAX_PATH];
  1280.         char            strMapEntitiesVoidFile[_MAX_PATH];
  1281.  
  1282.         safe_strncpy(g_source, mapname_from_arg, _MAX_PATH);
  1283.         StripExtension(g_source);
  1284.  
  1285.         // try looking in the current directory
  1286.         safe_strncpy(strSystemEntitiesVoidFile, ENTITIES_VOID, _MAX_PATH);
  1287.         if (!q_exists(strSystemEntitiesVoidFile))
  1288.         {
  1289.             char tmp[_MAX_PATH];
  1290.             // try looking in the directory we were run from
  1291. #ifdef SYSTEM_WIN32
  1292.             GetModuleFileName(NULL, tmp, _MAX_PATH);
  1293. #else
  1294.             safe_strncpy(tmp, argv[0], _MAX_PATH);
  1295. #endif
  1296.             ExtractFilePath(tmp, strSystemEntitiesVoidFile);
  1297.             safe_strncat(strSystemEntitiesVoidFile, ENTITIES_VOID, _MAX_PATH);
  1298.         }
  1299.  
  1300.         // Set the optional level specific lights filename
  1301.         safe_strncpy(strMapEntitiesVoidFile, g_source, _MAX_PATH);
  1302.         DefaultExtension(strMapEntitiesVoidFile, ENTITIES_VOID_EXT);
  1303.  
  1304.         LoadAllowableOutsideList(strSystemEntitiesVoidFile);    // default entities.void
  1305.         if (*strMapEntitiesVoidFile)
  1306.         {
  1307.             LoadAllowableOutsideList(strMapEntitiesVoidFile);   // automatic mapname.void
  1308.         }
  1309.     }
  1310.  
  1311.     // BEGIN BSP
  1312.     start = I_FloatTime();
  1313.  
  1314.     ProcessFile(g_Mapname); 
  1315.  
  1316.     end = I_FloatTime();
  1317.     LogTimeElapsed(end - start);
  1318.     // END BSP
  1319.  
  1320.     FreeAllowableOutsideList();
  1321.  
  1322.     return 0;
  1323. }
  1324.